package writer;

import java.io.File;

import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

//import data.GpxData;
import data.Waypoint;

public class KmlWriter {
	private String outputFilePath;
	private List<Waypoint> waypoints;

	public KmlWriter(List<Waypoint>waypoints, String outputFilePath) {
		this.outputFilePath = outputFilePath;
		this.waypoints = waypoints;
	}

	/**
	 * Creates the output XML file out of the given DOM structure.
	 * 
	 * @param resultsDocument
	 *            resultsDocument
	 * @throws WriteGpxException
	 *             if the transformer from DOM to XML couldn't be created or the
	 *             resultsDocument couldn't become written
	 */
	public void createXmlFileFromDomDocument(Document resultsDocument)
			throws WriteGpxException {
		DOMSource xmlFileDOMSource = new DOMSource(resultsDocument);
		File resultsFile = new File(outputFilePath);
		StreamResult streamResult = new StreamResult(resultsFile);
		TransformerFactory transformerFactory = TransformerFactory
				.newInstance();

		Transformer transformer = null;
		try {
			transformer = transformerFactory.newTransformer();
		} catch (TransformerConfigurationException e) {
			throw new WriteGpxException("Couldn't create transformer.", e);
		}
		// remove XML header
		transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
		transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
		try {
			transformer.transform(xmlFileDOMSource, streamResult);
		} catch (TransformerException e) {
			throw new WriteGpxException("Couldn't write results file.", e);
		}
	}

	/**
	 * Writes the XML content in a DOM structure.
	 * 
	 * @param kmlDocument
	 *            The DOM document which should get content.
	 */
	public void writeDocumentContent(Document kmlDocument) {
		
		String lastColor = "none";
		String currentColor = "";
		String coordinates = "";
		Waypoint wpt;
		Double diff;
		Double highest = 0.;
		Double lowest = 100.;
		Double tmp;
		// create root node
		Element nodeKml = kmlDocument.createElement("kml");
		nodeKml.setAttribute("xmlns", "http://www.opengis.net/kml/2.2");
		Element documentNode = kmlDocument.createElement("Document");

		
		Element nameNode = kmlDocument.createElement("name");
		nameNode.setTextContent("GPS Referenced measurement");
		documentNode.appendChild(nameNode);	

		Element descNode = kmlDocument.createElement("description");
		descNode.setTextContent("This is a KML file generated to display a GPS referenced Meassurement. The line will chance its color depending on the value of the measurement");
		documentNode.appendChild(descNode);			
		
		
		//TODO fuer jeden style aufrufen
		Element style = createStyle(kmlDocument, "rot", "FF0000FF");
		documentNode.appendChild(style);
		style = createStyle(kmlDocument, "orangerot", "FF0045FF");
		documentNode.appendChild(style);
		style = createStyle(kmlDocument, "orange", "FF00A5FF");
		documentNode.appendChild(style);
		style = createStyle(kmlDocument, "darkyellow", "FF00F7FF");
		documentNode.appendChild(style);		
		style = createStyle(kmlDocument, "yellow", "FF00FFFF");
		documentNode.appendChild(style);		
		style = createStyle(kmlDocument, "greenyellow", "FF05F99C");
		documentNode.appendChild(style);		
		style = createStyle(kmlDocument, "green", "FF00FF00");		
		documentNode.appendChild(style);
		
		//placemark	
/*
	    <Placemark>
	      <name>Absolute Extruded</name>
	      <description>Transparent green wall with yellow outlines</description>
	      <styleUrl>#yellowLineGreenPoly</styleUrl>
	      <LineString>
	        <extrude>1</extrude>
	        <tessellate>1</tessellate>
	        <altitudeMode>absolute</altitudeMode>
	        <coordinates> -112.2550785337791,36.07954952145647,2357
	          -112.2549277039738,36.08117083492122,2357
	          -112.2552505069063,36.08260761307279,2357
	          -112.2564540158376,36.08395660588506,2357
	          -112.2580238976449,36.08511401044813,2357
	          -112.2595218489022,36.08584355239394,2357
	          -112.2608216347552,36.08612634548589,2357
	          -112.262073428656,36.08626019085147,2357
	          -112.2633204928495,36.08621519860091,2357
	          -112.2644963846444,36.08627897945274,2357
	          -112.2656969554589,36.08649599090644,2357 
	        </coordinates>
	      </LineString>
	    </Placemark>
*/		
//		Element placemarkNode = kmlDocument.createElement("Placemark"); 
		Element styleUrlNode = kmlDocument.createElement("styleUrl");

		Element coordinatesNode = kmlDocument.createElement("coordinates");
		Element altitudeModeNode = kmlDocument.createElement("altitudeMod");

		Element lineStringNode = kmlDocument.createElement("LineString");

		for(int i = 0; i < waypoints.size(); i ++)
		{
			wpt = waypoints.get(i);
			if(highest < wpt.getName()){ highest = wpt.getName();}
			if(lowest > wpt.getName()){ lowest = wpt.getName();}
		}
		for(int i = 0; i < waypoints.size(); i ++)
		{
			wpt = waypoints.get(i);
			diff = (highest - lowest)/7;
			tmp = wpt.getName();
			// last color 
			// if color == then add else close and create new
			if(tmp > lowest + diff*6){ currentColor = "green";}

			else if(tmp > (lowest + diff*5)){ currentColor = "greenyellow";}

			else if(tmp > (lowest + diff*4)){ currentColor = "yellow";}
		
			else if(tmp > (lowest + diff*3)){ currentColor = "darkyellow";}

			else if(tmp > (lowest + diff*2)){ currentColor = "orange";}

			else if(tmp > (lowest + diff)){	currentColor = "orangerot";}	

			else { currentColor = "rot";}
			
			if(i == (waypoints.size() -1) ) 
			{
				
				Element placemarkNode = createPlacemark(kmlDocument, lastColor, coordinates);
				documentNode.appendChild(placemarkNode);

				
			}
			else
			{
				if(currentColor != lastColor && lastColor !="none") 
				{

					//create Placemark attributes
					Element placemarkNode = createPlacemark(kmlDocument, lastColor, coordinates);
					documentNode.appendChild(placemarkNode);					
					
					lastColor = currentColor;
					coordinates = wpt.getCoordinates();						
				}
				else
				{
					coordinates = coordinates + wpt.getCoordinates();
					lastColor = currentColor;
				
				}
			}
			
		}
		
		nodeKml.appendChild(documentNode);
		kmlDocument.appendChild(nodeKml);		
	}

	private Element createStyle(Document kmlDocument, String styleId, String color) {
		
		Element styleNode = kmlDocument.createElement("Style");
		styleNode.setAttribute("id", styleId);
		
		Element lineStyleNode = kmlDocument.createElement("LineStyle");

		Element colorNode = kmlDocument.createElement("color");
		colorNode.setTextContent(color);
		lineStyleNode.appendChild(colorNode);

		Element widthNode = kmlDocument.createElement("width");
		widthNode.setTextContent("8");
		lineStyleNode.appendChild(widthNode);
		//anfuegen an root node


		styleNode.appendChild(lineStyleNode);
		
		Element polyStyleNode = kmlDocument.createElement("PolyStyle");		
		Element polyColorNode = kmlDocument.createElement("color");
		polyColorNode.setTextContent(color);		
		polyStyleNode.appendChild(polyColorNode);		
		styleNode.appendChild(polyStyleNode);	
		
		return styleNode;
	}

	private Element createPlacemark(Document kmlDocument, String lastColor,String coordinates)
	{
		Element styleUrlNode = kmlDocument.createElement("styleUrl");
		Element placemarkNode = kmlDocument.createElement("Placemark"); 
		Element coordinatesNode = kmlDocument.createElement("coordinates");
		Element altitudeModeNode = kmlDocument.createElement("altitudeMod");

		Element lineStringNode = kmlDocument.createElement("LineString");
		
		styleUrlNode.setTextContent("#" + lastColor);

		placemarkNode.appendChild(styleUrlNode);
		
		//create LineString attributes
		altitudeModeNode.setTextContent("clampToGround");					
		lineStringNode.appendChild(altitudeModeNode);
		coordinatesNode.setTextContent(coordinates);
		lineStringNode.appendChild(coordinatesNode);
			
		placemarkNode.appendChild(lineStringNode);	
		
		return placemarkNode;
	}		
	

	/**
	 * Writes the XML file with the data which is accessible by this class.
	 * 
	 * @throws WriteGpxException
	 *             if the XML document builder couldn't be created or if errors
	 *             occur during the creation of the xml output file.
	 */
	public void writeXmlFile() throws WriteGpxException {
		// get Factory
		DocumentBuilderFactory xmlBuilderFactory = DocumentBuilderFactory
				.newInstance();
		DocumentBuilder xmlBuilder = null;
		try {
			// create new document builder
			xmlBuilder = xmlBuilderFactory.newDocumentBuilder();
		} catch (ParserConfigurationException e) {
			throw new WriteGpxException("Couldn't create DocumentBuilder.", e);
		}

		// create new XML document
		Document resultsDocument = xmlBuilder.newDocument();

		writeDocumentContent(resultsDocument);

		createXmlFileFromDomDocument(resultsDocument);
	}
}
